use actix_service::{Service, Transform};
use std::task::{Context, Poll};
use actix_web::{dev::ServiceRequest, dev::ServiceResponse, Error, error};
use std::cell::RefCell;
use std::rc::Rc;
use std::pin::Pin;
use actix_web::body::MessageBody;
use actix_web::http::HeaderValue;

use futures_util::future::{ok, Either, FutureExt, LocalBoxFuture};

pub struct JWT;

impl<S, B> Transform<S> for JWT
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error>,
    S::Future: 'static,
    B: MessageBody + 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Transform = JWTMiddleware<S>;
    type InitError = ();
    type Future = LocalBoxFuture<'static, Result<Self::Transform, Self::InitError>>;

    fn new_transform(&self, service: S) -> Self::Future {
        ok(JWTMiddleware { service:Rc::new(RefCell::new(service)) })
    }
}



pub struct JWTMiddleware<S> {
    service: Rc<RefCell<S>>,
}

impl<S, B> Service for JWTMiddleware<S>
where
    S: Service<Request = ServiceRequest, Response = ServiceResponse<B>, Error = Error> + 'static,
    S::Future: 'static,
    B: MessageBody+ 'static,
{
    type Request = ServiceRequest;
    type Response = ServiceResponse<B>;
    type Error = Error;
    type Future = Pin<Box<dyn Future<Output = Result<Self::Response, Self::Error>>>>;

    fn poll_ready(&mut self, cx: &mut Context<'_>) -> Poll<Result<(), Self::Error>> {
        self.service.poll_ready(cx)
    }

    fn call(&mut self, req: ServiceRequest) -> Self::Future {
        println!("Hi from start. You requested: {}", req.path());

        let mut svc = self.service.clonse();

        Box::pin(async move {
            let value = HeaderValue::from_str("").unwrap();
            let token = req.headers().get("token").unwrap_or(&value);
            if token.len() > 0 {
                Ok(svc.call(req).await?)
            } else {
                Err(error::ErrorUnauthorized("err"))
            }
        })
    }
}